#pragma once

#include"Socket.hpp"
#include"Logger.hpp"
#include"Protocol.hpp"
#include<memory>
#include<iostream>
#include<string>
#include<unistd.h>
#include<signal.h>
#include<functional>

using callback_t = std::function<std::string(std::string&)>;

class TcpServer
{
private:
    void HandlerRequest(std::shared_ptr<Socket> sockfd , InetAddr client)
    {
        std::string inbuffer;//接受缓冲区
        while(true)
        {
            ssize_t n = sockfd->Recv(&inbuffer);
            if(n >0)
            {
                //只要读到数据就交给外层处理,
                std::string send_str = _cb(inbuffer);
                if(send_str.empty()) continue;
                else
                {
                    //写回
                    sockfd->Send(send_str);
                }

            }
            else if(n==0)
            {
                LOG(LogLevel::ERROR) << "client : " << client.ToString() << " 退出， me too";
                break; 
            }
            else
            {
                LOG(LogLevel::FATAL) << "recv error , client: " << client.ToString();
                break; 
            }
        }
        sockfd->Close();
    }
public:
    TcpServer(uint16_t port , callback_t cb)
    :_port(port) , _cb(cb)
    ,_listensockfd(std::make_unique<TcpSocket>())
    {
        //在构建服务器对象的时候就创建其对应的监听套接字
        _listensockfd->BuildTcpSocketServer(_port);
    }
    ~TcpServer(){}

    void Run()
    {
        signal(SIGCHLD , SIG_IGN);
        //让服务器跑起来，此处处理为长服务
        while(true)
        {
            InetAddr clientaddr(_port);
            //获取连接
            std::shared_ptr<Socket> sockfd = _listensockfd->Accept(&clientaddr);
            //判断获取连接是否成功
            if(sockfd == nullptr) continue;

            //到了此处就是获取连接成功，从sockfd 中读取数据 --> 交给其他函数去处理
            LOG(LogLevel::DEBUG) << "获取连接成功：" << clientaddr.ToString() << ", sockfd: " << sockfd->Sockfd();

            //创建子进程，让子进程去执行IO，并且父进程不等待子进程
            if(fork()==0)
            {
                _listensockfd->Close();
                HandlerRequest(sockfd ,clientaddr);

                exit(0);//子进程执行完io就退出
            }
            //父进程关闭不适用的文件描述符 --> 避免误操作以及文件描述符的泄漏
            sockfd->Close();
        }
    }

private:
    //指向套接字的智能指针
    std::unique_ptr<Socket> _listensockfd;
    uint16_t _port;
    callback_t _cb;
};